package com.alex.statistics.method.clusterAnalysis;


import com.alex.statistics.pojo.request.clusterAnalysis.CorrelationAnalysisRequest;
import com.alex.statistics.pojo.result.clusterAnalysis.CorrelationAnalysisResult;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

@Service
public class CorrelationAnalysisService {

    public CorrelationAnalysisResult analyze(CorrelationAnalysisRequest request) {
        long startTime = System.currentTimeMillis();

        // 参数校验
        validateRequest(request);

        // 数据准备
        List<double[]> data = request.getData();
        String method = request.getMethod();
        List<String> variableNames = request.getVariableNames();
        if (variableNames == null) {
            variableNames = new ArrayList<>();
            for (int i = 0; i < data.size(); i++) {
                variableNames.add("变量" + (i + 1));
            }
        }

        // 计算相关系数矩阵
        int n = data.size();
        double[][] correlationMatrix = new double[n][n];

        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                if (i == j) {
                    correlationMatrix[i][j] = 1.0;
                } else {
                    double corr = calculateCorrelation(data.get(i), data.get(j), method);
                    correlationMatrix[i][j] = corr;
                    correlationMatrix[j][i] = corr;
                }
            }
        }

        // 构建热力图数据
        List<CorrelationAnalysisResult.HeatmapPoint> heatmapData = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                heatmapData.add(new CorrelationAnalysisResult.HeatmapPoint(
                        variableNames.get(i),
                        variableNames.get(j),
                        correlationMatrix[i][j]
                ));
            }
        }

        // 构建结果
        CorrelationAnalysisResult result = new CorrelationAnalysisResult();
        result.setCorrelationMatrix(correlationMatrix);
        result.setHeatmapData(heatmapData);
        result.setVariableNames(variableNames);
        result.setComputeTime(System.currentTimeMillis() - startTime);

        return result;
    }

    private double calculateCorrelation(double[] x, double[] y, String method) {
        switch (method.toLowerCase()) {
            case "pearson":
                return pearsonCorrelation(x, y);
            case "spearman":
                return spearmanCorrelation(x, y);
            case "kendall":
                return kendallCorrelation(x, y);
            default:
                throw new IllegalArgumentException("不支持的相关系数计算方法: " + method);
        }
    }

    private double pearsonCorrelation(double[] x, double[] y) {
        int n = x.length;
        double sumX = 0.0, sumY = 0.0, sumXY = 0.0;
        double sumX2 = 0.0, sumY2 = 0.0;

        for (int i = 0; i < n; i++) {
            sumX += x[i];
            sumY += y[i];
            sumXY += x[i] * y[i];
            sumX2 += x[i] * x[i];
            sumY2 += y[i] * y[i];
        }

        double numerator = n * sumXY - sumX * sumY;
        double denominator = Math.sqrt((n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY));

        if (denominator == 0) {
            return 0.0;
        }

        return numerator / denominator;
    }

    private double spearmanCorrelation(double[] x, double[] y) {
        int n = x.length;
        double[] rankX = computeRanks(x);
        double[] rankY = computeRanks(y);

        // 计算等级差的平方和
        double sumD2 = 0.0;
        for (int i = 0; i < n; i++) {
            double d = rankX[i] - rankY[i];
            sumD2 += d * d;
        }

        // 计算Spearman相关系数
        return 1.0 - (6.0 * sumD2) / (n * (n * n - 1));
    }

    private double[] computeRanks(double[] data) {
        int n = data.length;
        RankedValue[] rankedValues = new RankedValue[n];

        for (int i = 0; i < n; i++) {
            rankedValues[i] = new RankedValue(data[i], i);
        }

        // 按值排序
        Arrays.sort(rankedValues, Comparator.comparingDouble(v -> v.value));

        // 分配等级
        double[] ranks = new double[n];
        for (int i = 0; i < n; ) {
            double currentValue = rankedValues[i].value;
            int j = i;
            while (j < n && rankedValues[j].value == currentValue) {
                j++;
            }
            double rank = (i + j + 1) / 2.0;
            for (int k = i; k < j; k++) {
                ranks[rankedValues[k].index] = rank;
            }
            i = j;
        }

        return ranks;
    }

    private static class RankedValue {
        double value;
        int index;

        public RankedValue(double value, int index) {
            this.value = value;
            this.index = index;
        }
    }

    private double kendallCorrelation(double[] x, double[] y) {
        int n = x.length;
        int concordant = 0;
        int discordant = 0;

        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                double dx = x[i] - x[j];
                double dy = y[i] - y[j];

                if ((dx > 0 && dy > 0) || (dx < 0 && dy < 0)) {
                    concordant++;
                } else if ((dx > 0 && dy < 0) || (dx < 0 && dy > 0)) {
                    discordant++;
                }
            }
        }

        return (double) (concordant - discordant) / (concordant + discordant);
    }

    private void validateRequest(CorrelationAnalysisRequest request) {
        if (request.getData() == null || request.getData().isEmpty()) {
            throw new IllegalArgumentException("数据不能为空");
        }
        if (request.getMethod() == null || !request.getMethod().toLowerCase().matches("pearson|spearman|kendall")) {
            throw new IllegalArgumentException("不支持的相关系数计算方法，支持的选项: pearson, spearman, kendall");
        }
        if (request.getVariableNames() != null && request.getVariableNames().size() != request.getData().size()) {
            throw new IllegalArgumentException("变量名数量必须与数据列数一致");
        }
    }
}    